///////////////////////////////////////////////////////////////////////////////
////  (c) Chaichuk AU (chaichuk@mail.ru), 								   ////
////  2004, Chelyabinsk, NTC Privodnaya Tehnika (momentum@chel.surnet.ru)  ////
///////////////////////////////////////////////////////////////////////////////

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <time.h>
#include <math.h>
#include <hw/pci.h>
#include <hw/pci_devices.h>

#include "ctnet_io.h"
#include "arcdef.h"
#include "arc20.h"

char* get_time_now ()
{
	time_t tod;
	static char out [100];
	
	time (&tod);
    strftime (out, sizeof (out), "%d-%m-%Y %T", localtime (&tod));	
    
    return out;
}

int init_device (arc20_t *arc20)
{
/*	void* hdl;
    int pidx;
    int phdl;
    struct pci_dev_info inf;

    /* Connect to the PCI server */
/*    phdl = pci_attach (0);
    if (phdl == -1) {
        fprintf( stderr, "Unable to initialize PCI\n" );
        return EXIT_FAILURE;
    }

    /* Initialize the pci_dev_info structure */
/*    memset (&inf, 0, sizeof (inf));
    pidx = 0;
    inf.VendorId = 0x1571; // Conterporary Controls
    inf.DeviceId = 0xA00B; // CCSI PCI20-5-485X 5Mbit ARCNet

	hdl = pci_attach_device (NULL, PCI_INIT_ALL | PCI_SHARE, pidx, &inf);
    if (hdl == NULL) {
        perror ("Unable to locate adapter");
        pci_detach_device (hdl);
        return (-1);
    } 
   	printf ("CCSI PCI20-5-485X 5Mbit ARCNet device found !!\n");		
	printf ("Base Addr = %Xh, ", (uint_t) PCI_IO_ADDR  (inf.PciBaseAddress [2]));		
	printf ("IRQ = %Xh\n", (uint_t) inf.Irq);	
	arc20_init (arc20, PCI_IO_ADDR (inf.PciBaseAddress [2]), inf.Irq);		
	pci_detach_device (hdl);	
*/

	arc20_init (arc20, 0x2e0, 0);		

	return 0;	
}

int send_request (arc20_t *arc20, uint8_t src_ID, uint8_t dst_ID, const uint8_t *msg, const int len)
{
	uint8_t buf [512];
	int status;
	
	buf [0] = src_ID; 				// SID
	buf [1] = dst_ID; 				// DID
	buf [2] = (uint8_t) (len >> 8); // msblen
	buf [3] = (uint8_t) len;		// lsblen 
	memcpy (&buf [4], msg, len);	// data

	status = arc20_write (arc20, buf);	
	if (status == E_TX_BUSY) {
		fprintf (stderr, "Transmitter Busy\n");
		return (-1);
	}

	return 0;
}	

int read_response (arc20_t *arc20, uint8_t *src_ID, uint8_t *msg, int *len)
{
	uint8_t buf [512];
	int status;
	int count;

	status = arc20_read (arc20, buf);
	if (status != E_OK) {
		fprintf (stderr, "Error while receiving message\n");
		return (-1);
	}
	
	// packet format SID, DID, msbcount, lsbcount, data,...
	*src_ID = buf [0];
	count = buf [3];
	if (buf [2] > 0) count += 256;
	*len = count;
	memcpy (msg, &buf [4], count);
	
	return 0; 	
}

int CTNET_param_read (arc20_t *arc20, uint8_t dst_ID, int n_param, uint8_t *menu, uint8_t *param, float *buf)
{
	uint8_t msg [512];
	int len = 6 + (n_param * 4);
	int i;
	int ofs;
	uint8_t src_ID = 0;
	static uint8_t cnt;	
	
	msg [0] = 0x82;
	msg [1] = 0x14;
	msg [2] = 0x00;
	
	msg [3] = ++cnt;	
	msg [4] = n_param;
	msg [5] = 2 + (n_param * 4);
	
	for (i=0; i<n_param; i++) {
		msg [6+4*i] = 0x01;
		msg [7+4*i] = param [i];
		msg [8+4*i] = menu  [i];
		msg [9+4*i] = 0x00;	
	}	
	
	send_request (arc20, arc20->nodeid, dst_ID, msg, len);
//	delay (10);
//	read_response (arc20, &src_ID, msg, &len);
	while (read_response (arc20, &src_ID, msg, &len) != 0);
	if ((cnt - 1) == msg [3]) read_response (arc20, &src_ID, msg, &len);
	
	if (src_ID != dst_ID) {
		fprintf (stderr, "Wrong message src_ID (expected from %d, received from %d)\n", dst_ID, src_ID);
		return (-1);
	}	
	if ((msg [0] != 0x82)&& (msg [1] != 0x14)&& (msg [2] != 0x01)) {
		fprintf (stderr, "Wrong message header\n");
		return (-1);
	}
	if (msg [3] != cnt) {
		fprintf (stderr, "Wrong cnt (expected %d, received %d)\n", cnt, msg [3]);
		return (-1);
	}
	if (msg [5] != (msg [4] * 9) + 2) {
		fprintf (stderr, "Message with unknown errors\n");
		return (-1);
	}

	for (i=0; i<msg [4]; i++) {
		ofs = 4*i;
		if (msg [6 + ofs] != 0x01) fprintf (stderr, "Error 01\n");
		if (msg [7 + ofs] != param [i]) fprintf (stderr, "Error - param\n");
		if (msg [8 + ofs] != menu  [i]) fprintf (stderr, "Error - menu\n");
		if (msg [9 + ofs] != 0x00) fprintf (stderr, "Error 00\n");
	}
	
	for (i=0; i<msg [4]; i++) {
		ofs = 4*msg [4] + 5*i;
		buf [i]  = msg [6 + ofs];
		buf [i] += msg [7 + ofs] << 8;		
		buf [i] += msg [8 + ofs] << 16;		
		buf [i] += msg [9 + ofs] << 24;		
		buf [i] *= powf (10, (float) (2 - msg [10 + ofs])); 		
	}
	
	return 0;
}